#ifndef _MUNIX_RBUFF_H_
#define _MUNIX_RBUFF_H_
/*******************************************************************************
 ** Name: types.h                                                             **
 ** Description:              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the license.txt within              **
 ** this distribution or at http://www.munixos.net/licensing.                 **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $HOME/license.txt.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 **                                                                           **
 ** Copyright (c) 2009-2010  Barry Gian James <bjames@munixos.net>            **
 ** All rights reserved.                                                      **
 **                                                                           **
 ** Ref: $HeadURL$
 ******************************************************************************/
// Portions (C) 2011-12 Open Design Strategies, LLC.
// All Rights Reserved

// $Id$
// Last Modified $DateTime$ by $Author$

#include "common.h"
#include <string.h>


#define DEFAULT_RING_BUFF_SZ	16	// power of 2!!

//! @class ring_buffer_basic
//! @brief Implements a queue or circular buffer
template <class T>
class ring_buffer_basic
{
public:
	ring_buffer_basic(uint8_t sz);
        ring_buffer_basic(const ring_buffer_basic &);
	~ring_buffer_basic() { clear();}

	// Accessors
	void	push(T &) volatile;
	T		pop() volatile;
	void	resize(uint8_t sz);

	// Getters
    volatile T & head() const { return _buff[_head]; }
    volatile T& tail() const { return _buff[_tail]; }
	const bool	empty() const { return (_head == _tail); }
	const uint8_t	size() const { return _sz; }
	const uint8_t	length() const { return _len; }

	void	clear();
	class Node;
	const Node *	data() const { return _buff; }


private:
        struct Node
        {
        	T	data;

        	bool operator == (const Node & n) {
        		return _head == _tail;
        	}
        };
	volatile Node   *_buff;
	uint8_t		_sz;
	volatile uint8_t	_head;
	volatile	uint8_t	_tail;
	volatile uint8_t	_len;

	void		_copybuff(const ring_buffer_basic &);

};

template<class T>
void
ring_buffer_basic<T>::resize(uint8_t sz)
{
	clear();

	_sz = sz;
	_buff = new volatile Node[_sz];
	for(int i = 0; i < _sz; i++)
		_buff[i] = new volatile Node;

	_head = _tail = _len = 0;
}

template<class T>
void
ring_buffer_basic<T>::clear()
{
	for (int i = 0; i <= _sz; i++)
		delete _buff[i];

	delete _buff;

	_head = _tail = _len = 0;
}

template<class T>
ring_buffer_basic<T>::ring_buffer_basic<T>(uint8_t sz)
{
	_sz = sz;
	_buff = new volatile Node[_sz];
	for(int i = 0; i < _sz; i++)
		_buff[i] = new volatile Node;

	_head = _tail = _len = 0;

}
template<class T>
ring_buffer_basic<T>::ring_buffer_basic(const ring_buffer_basic& rb)
{
	clear();
	_buff = new volatile Node[rb.size()];
    _copybuff(rb);
}

template<class T>
void
ring_buffer_basic<T>::_copybuff(const ring_buffer_basic & rb)
{
	// Ok, let's do it
	const Node * rbn = rb.data();
	for(int i = 0; i < rb.size(); i++)
		_buff[i].data = rbn[i].data;
}

// Pop from the head
template<class T>
T
ring_buffer_basic<T>::pop() volatile
{
	if (_len == 0)
		return 0;

	T c = _buff[_head].data;

	if (_head >= _sz) _head = 0;
	--_len;

	return c;
}

// Push onto the tail
template<class T>
void
ring_buffer_basic<T>::push(T & t) volatile
{
	_buff[_tail++].data = t;
	if (_tail >= _sz) _tail = 0;
	++_len;
}


#endif	/* _MUNIX_RBUFF_H_ */


